home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 6 / develop 6 code / TCP / NewsWatcher / NewsWatcher 2.0d15 source / source / message.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-30  |  14.9 KB  |  650 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     message.c
  4.  
  5.     This module handles the creation of message windows.
  6.     
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <Script.h>
  15.  
  16. #include "MacTCPCommonTypes.h"
  17. #include "TCPPB.h"
  18.  
  19. #include "dlgutil.h"
  20. #include "glob.h"
  21. #include "header.h"
  22. #include "message.h"
  23. #include "open.h"
  24. #include "resize.h"
  25. #include "scroll.h"
  26. #include "tcp.h"
  27. #include "util.h"
  28.  
  29.  
  30.  
  31. #define kPostAlert            135            /* Post confirm dialog */
  32. #define kPostDlg            136            /* Post dialog */
  33. #define kRespDlg            137            /* Mail dialog */
  34.  
  35.  
  36.  
  37. static void CheckSubject (char *subject)
  38. {
  39.     if (*subject == 0)
  40.         ErrorMessage("Please supply a Subject!");
  41. }
  42.  
  43.  
  44. static void CheckNewsgroups (char *newsgroups)
  45. {
  46.     if (*newsgroups == 0)
  47.         ErrorMessage("You MUST supply Newsgroups!");
  48. }
  49.  
  50.  
  51. static OSErr MakeMsgId (char *MsgId)
  52. {
  53.     DateTimeRec    DateTime;
  54.     CStr255    HostName;
  55.     short    i;
  56.     OSErr    err;
  57.  
  58.     *MsgId = 0;
  59.     if(*gPrefs.address == 0)    return(-1);
  60.     if((err = GetMyIPName(HostName)) != noErr)
  61.     {
  62.         if((err = GetMyIPAddrStr(HostName)) != noErr) return(err);
  63.     }
  64.     /*    Isolate the first part of the mail address    */
  65.     for(i=0; (gPrefs.address)[i] != 0 && (gPrefs.address)[i] != '@' && 
  66.         (gPrefs.address)[i] != '%' && (gPrefs.address)[i] != '!'; i++);
  67.     if(*HostName == 0)    return(-1);
  68.     GetTime(&DateTime);
  69.     sprintf(MsgId,"<%.*s-%.2i%.2i%.2i%.2i%.2i%.2i@%s>",
  70.                     i, gPrefs.address,
  71.                     DateTime.day,
  72.                     DateTime.month,
  73.                     DateTime.year%100,
  74.                     DateTime.hour,
  75.                     DateTime.minute,
  76.                     DateTime.second,
  77.                     HostName);
  78.     return(noErr);
  79. }
  80.  
  81.  
  82. /*    InitHeaderDisplay intializes the header display for a message window
  83.     (header shown or hidden)
  84. */
  85.  
  86. static void InitHeaderDisplay (WindowPtr wind)
  87. {
  88.     TWindow **info;
  89.     
  90.     info = (TWindow**)GetWRefCon(wind);
  91.     (**info).headerShown = true;
  92.     if (gPrefs.showHeaders) return;
  93.     DoShowHideHeader(wind);
  94. }
  95.  
  96. /*    Present "are you sure you want to post" alert. */
  97.  
  98. static Boolean AreYouSure (void)
  99. {
  100.     DialogPtr dlg;
  101.     short item;
  102.  
  103.     if (!gPrefs.areYouSureAlert) return true;
  104.     dlg = MyGetNewDialog(kPostAlert);
  105.     MyModalDialog(DialogFilter, &item, true, true);
  106.     MyDisposDialog(dlg);
  107.     return (item == ok);
  108. }
  109.  
  110.  
  111. /*    IncludeQuote indents and includes the article to which the user is 
  112.     responding in the new article template.
  113. */
  114.  
  115. static void IncludeQuote (WindowPtr parentWindow,
  116.     WindowPtr newWindow, char refStr[4096])
  117. {
  118.     Handle text;
  119.     TEHandle theTE;
  120.     long teLength;
  121.     short length;
  122.     long offset;
  123.     TWindow **info;
  124.     CStr255 article, sender, mungeStr;
  125.     char tmpStr[4096], *ptr;
  126.     EWindowKind kind;
  127.     
  128.     info = (TWindow**) GetWRefCon(parentWindow);
  129.     text = (**info).fullText;
  130.     
  131.     info = (TWindow**) GetWRefCon(newWindow);
  132.     theTE = (**info).theTE;
  133.     kind = (**info).kind;
  134.  
  135.     FindHeader(text,"Message-ID:",article, sizeof(article));
  136.     if (kind == kPostMessage) {
  137.         FindHeader(text,"From:",sender, sizeof(sender));
  138.     } else {
  139.         strcpy(sender, "you");
  140.     }
  141.     FindHeader(text,"References:",tmpStr, sizeof(tmpStr));
  142.  
  143.     ptr = tmpStr;
  144.     length = strlen(article);
  145.     while(*ptr && (strlen(ptr) + length > 4094)) {
  146.         while(*ptr && *ptr != '<')    ptr++;
  147.     }
  148.     strcpy(refStr,ptr);
  149.     if (*refStr != 0) strcat(refStr," ");
  150.     strcat(refStr,article);
  151.     
  152.     if (MyHandToHand(&text) != noErr) return;
  153.     if (MyMemErr() != noErr) return;
  154.     
  155.     offset = Munger(text,0,CRCR,2,nil,0) + 1;
  156.     offset = Munger(text,0,nil,offset,"*",0);
  157.     strcpy(mungeStr,CRSTR);
  158.     strcat(mungeStr,"> ");
  159.     while ( (offset = Munger(text,offset,CRSTR,1,mungeStr,3)) >= 0)
  160.         ;
  161.     offset = Munger(text,0,nil,0,"In article ",11);
  162.     offset = Munger(text,offset,nil,0,article,strlen(article));
  163.     offset = Munger(text,offset,nil,0,", ",2);
  164.     offset = Munger(text,offset,nil,0,sender,strlen(sender));
  165.     offset = Munger(text,offset,nil,0," wrote:",7);
  166.     offset = Munger(text,offset,nil,0,CRSTR,1);
  167.     
  168.     teLength = GetHandleSize(text);
  169.     if (teLength > 25000) {
  170.         MySetHandleSize(text,25000);
  171.         teLength = 25000;
  172.         ErrorMessage("Quoted text too long - truncated.");
  173.     }
  174.     HLock(text);
  175.     TESetText(*text,teLength,theTE);
  176.     TESetSelect(0,0,theTE);
  177.     MyDisposHandle(text);
  178. }
  179.  
  180.  
  181. /*    AddEmptyLine adds an empty line after the headers    */
  182.  
  183. static void AddEmptyLine (WindowPtr newWindow)
  184. {
  185.     TEHandle theTE;
  186.     TWindow **info;
  187.     
  188.     info = (TWindow**)GetWRefCon(newWindow);
  189.     theTE = (**info).theTE;
  190.     
  191.     TEInsert(CRSTR,1,theTE);
  192. }
  193.  
  194. /*    AddHeader adds a header of name hName and contents hContents to the
  195.     TextEdit field in window newWindow.
  196. */
  197.  
  198. static void AddHeader (char *hName, char *hContents, WindowPtr newWindow)
  199. {
  200.     TEHandle theTE;
  201.     TWindow **info;
  202.     
  203.     info = (TWindow**)GetWRefCon(newWindow);
  204.     theTE = (**info).theTE;
  205.     
  206.     if(*hContents == 0) return;
  207.     
  208.     TEInsert(hName,strlen(hName),theTE);
  209.     TEInsert(hContents,strlen(hContents),theTE);
  210.     TEInsert(CRSTR,1,theTE);
  211. }
  212.  
  213.  
  214. static void AddDateHeader (WindowPtr newWindow)
  215. {
  216.     static char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  217.     static char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
  218.                              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  219.  
  220.     DateTimeRec date;
  221.     MachineLocation loc;
  222.     long gmtDelta;
  223.     char gmtSign;
  224.     short gmtHours;
  225.     short gmtMinutes;
  226.     CStr255 dateHeader;
  227.     
  228.     ReadLocation(&loc);
  229.     if (loc.latitude == 0 && loc.longitude == 0 && loc.gmtFlags.gmtDelta == 0) return;
  230.     gmtDelta = loc.gmtFlags.gmtDelta & 0x00ffffff;
  231.     if ((gmtDelta >> 23) & 1) gmtDelta |= 0xff000000;
  232.     if (gmtDelta < 0) {
  233.         gmtSign = '-';
  234.         gmtDelta = -gmtDelta;
  235.     } else {
  236.         gmtSign = '+';
  237.     }
  238.     gmtHours = gmtDelta / 3600;
  239.     gmtMinutes = (gmtDelta % 3600) / 60;
  240.     GetTime(&date);
  241.     sprintf(dateHeader, "%s, %.2d %s %.4d %.2d:%.2d:%.2d %c%.2d%.2d",
  242.         days[date.dayOfWeek - 1],
  243.         date.day,
  244.         months[date.month - 1],
  245.         date.year,
  246.         date.hour,
  247.         date.minute,
  248.         date.second,
  249.         gmtSign,
  250.         gmtHours,
  251.         gmtMinutes
  252.     );
  253.     AddHeader("Date: ", dateHeader, newWindow);
  254. }
  255.  
  256.  
  257. /*    AddSignature adds the signature, if any, to the
  258.     TextEdit field in window newWindow.
  259. */
  260.  
  261. static void AddSignature (WindowPtr newWindow)
  262. {
  263.     TEHandle theTE;
  264.     long tePos;
  265.     TWindow **info;
  266.     
  267.     info = (TWindow**)GetWRefCon(newWindow);
  268.     theTE = (**info).theTE;
  269.     
  270.     if (*gPrefs.signature != 0 && strlen(gPrefs.signature) != 0) {
  271.         tePos = (**theTE).selStart;
  272.         TESetSelect(0x7fff,0x7fff,theTE);
  273.         TEInsert(CRSTR,1,theTE);
  274.         TEInsert(CRSTR,1,theTE);
  275.         if (gPrefs.addSigSeparatorLine) {
  276.             TEInsert("-- ",3,theTE);
  277.             TEInsert(CRSTR,1,theTE);
  278.         }
  279.         TEInsert(gPrefs.signature,strlen(gPrefs.signature),theTE);
  280.         TEDeactivate(theTE);
  281.         (**theTE).clikStuff = 255;
  282.         TESetSelect(tePos,tePos,theTE);
  283.         TEActivate(theTE);
  284.     }
  285. }
  286.  
  287.  
  288. /*    FixGroupList takes a comma or space separated list of group names
  289.     and replaces it by a comma separated list with no spaces. */
  290.  
  291. static void FixGroupList (char *str)
  292. {
  293.     char *p, *q;
  294.     
  295.     for (p = q = str; *p; p++) {
  296.         if (*p == ' ') {
  297.             if (q > str && *(q-1) != ',') *q++ = ','; 
  298.         } else {
  299.             *q++ = *p;
  300.         }
  301.     }
  302.     *q = 0;
  303. }
  304.  
  305.  
  306. /*    MakeFollowUp creates a new article template for a follow-up back to
  307.     a newsgroup.
  308. */
  309.  
  310. void MakeFollowUp (WindowPtr wind)
  311. {
  312.     DialogPtr dlg;
  313.     short item;
  314.     TWindow **info;
  315.     WindowPtr newWind;
  316.     GrafPtr savePort;
  317.     Point firstOffset;
  318.     CStr255 groupStr,distStr,subjectStr,followStr;
  319.     CStr255 messageID,path,tmpStr;
  320.     char fromStr[515];
  321.     char refStr[4096];
  322.     short i;
  323.     Handle text;
  324.     
  325.     SetPt(&firstOffset,0,0);
  326.     GetPort(&savePort);
  327.     SetPort(wind);
  328.     LocalToGlobal(&firstOffset);
  329.     SetPort(savePort);
  330.  
  331.     if (!AreYouSure()) return;
  332.         
  333.     info = (TWindow**) GetWRefCon(wind);
  334.     text = (**info).fullText;
  335.  
  336.     if(FindHeader(text,"Followup-To:", followStr, sizeof(followStr))) {
  337.         if(strncasecmp(followStr,"poster",6) == 0) {
  338.             MakeRespond(wind);
  339.             return;
  340.         }
  341.         strcpy(groupStr,followStr);
  342.     } else if (FindHeader(text,"Newsgroups:", followStr, sizeof(followStr))) {
  343.         strcpy(groupStr,followStr);
  344.         for(i=0; i<strlen(groupStr); i++)
  345.             if(groupStr[i] == ',') groupStr[i] = 0;
  346.     }
  347.  
  348.     if(FindHeader(text,"Subject:",tmpStr, sizeof(subjectStr)-4)) {
  349.         strcpy(subjectStr,"Re: ");
  350.         if (strncasecmp(tmpStr,"Re: ",4) == 0) {
  351.             strcat(subjectStr, &tmpStr[4]);
  352.         } else {
  353.             strcat(subjectStr, tmpStr);
  354.         }
  355.     }
  356.  
  357.     if(!FindHeader(text,"Distribution:", distStr, sizeof(distStr))) {
  358.         strcpy(distStr, "");        
  359.     }
  360.  
  361.     dlg = MyGetNewDialog(kPostDlg);
  362.     
  363.     DlgSetCString(dlg, 3, groupStr);
  364.     DlgSetCString(dlg, 4, followStr);
  365.     DlgSetCString(dlg, 5, distStr);
  366.     DlgSetCString(dlg, 6, subjectStr);
  367.  
  368.     SelIText(dlg,6,0,32000);
  369.     
  370.     do {
  371.         DlgEnableItem(dlg, ok, *groupStr != 0 && *subjectStr != 0);
  372.         MyModalDialog(DialogFilter, &item, true, true);
  373.         DlgGetCString(dlg, 3, groupStr);
  374.         DlgGetCString(dlg, 6, subjectStr);
  375.     } while (item != ok && item != cancel);
  376.     
  377.     if (item == ok) {
  378.         DlgGetCString(dlg, 4, followStr);
  379.         DlgGetCString(dlg, 5, distStr);
  380.     }
  381.     
  382.     MyDisposDialog(dlg);
  383.     
  384.     if (item == cancel) return;
  385.     
  386.     FixGroupList(groupStr);
  387.     FixGroupList(followStr);
  388.     
  389.     strcpy(fromStr,gPrefs.address);
  390.     strcat(fromStr," (");
  391.     strcat(fromStr,gPrefs.fullName);
  392.     strcat(fromStr,")");
  393.     
  394.     c2pstr(subjectStr);
  395.     info = (TWindow**) GetWRefCon(newWind = 
  396.         MakeNewWindow(kPostMessage,firstOffset,(StringPtr)subjectStr));
  397.     p2cstr((StringPtr)subjectStr);
  398.  
  399.     (**info).changed = true;
  400.     IncludeQuote(wind,newWind,refStr);
  401.  
  402.     if(GetMyIPName(path) == noErr && strlen(path) <= 250) {
  403.         strcat(path,"!user");
  404.         AddHeader("Path: ",path,newWind);
  405.     } else {
  406.         AddHeader("Path: ","NewsWatcher!user",newWind);
  407.     }
  408.     AddDateHeader(newWind);
  409.     AddHeader("From: ",fromStr,newWind);
  410.     AddHeader("Newsgroups: ",groupStr,newWind);
  411.     AddHeader("Followup-To: ",followStr,newWind);
  412.     AddHeader("Distribution: ",distStr,newWind);
  413.     AddHeader("Subject: ",subjectStr,newWind);
  414.  
  415.     if(MakeMsgId(messageID) == noErr)
  416.         AddHeader("Message-ID: ", messageID, newWind);
  417.     AddHeader("References: ",refStr,newWind);
  418.     AddHeader("Organization: ",gPrefs.organization,newWind);
  419.     AddEmptyLine(newWind);
  420.  
  421.     CheckNewsgroups(groupStr);
  422.     CheckSubject(subjectStr);
  423.  
  424.     AddSignature(newWind);
  425.     InitHeaderDisplay(newWind);
  426.  
  427.     DoZoom(newWind,inZoomOut);
  428.     AdjustScrollBar(newWind);
  429.  
  430.     ShowWindow(newWind);
  431. }
  432.  
  433.  
  434. /*    MakeRespond creates a new message template for an e-mail response to
  435.     a news article.
  436. */
  437.  
  438. void MakeRespond (WindowPtr wind)
  439. {
  440.     DialogPtr dlg;
  441.     short item;
  442.     TWindow **info;
  443.     WindowPtr newWind;
  444.     Point firstOffset;
  445.     GrafPtr savePort;
  446.     CStr255 recipStr, subjectStr, tmpStr;
  447.     char refStr[4096], fromStr[515];
  448.     Handle text;
  449.  
  450.     SetPt(&firstOffset,0,0);
  451.     GetPort(&savePort);
  452.     SetPort(wind);
  453.     LocalToGlobal(&firstOffset);
  454.     SetPort(savePort);
  455.     
  456.     info = (TWindow**) GetWRefCon(wind);
  457.     text = (**info).fullText;
  458.  
  459.     if(FindHeader(text,"Subject:",tmpStr,sizeof(subjectStr)-4)) {
  460.         strcpy(subjectStr,"Re: ");
  461.         if (strncasecmp(tmpStr,"Re: ",4) == 0) {
  462.             strcat(subjectStr, &tmpStr[4]);
  463.         } else {
  464.             strcat(subjectStr, tmpStr);
  465.         }
  466.     }
  467.  
  468.     if (!FindHeader(text,"Reply-To:",recipStr, sizeof(recipStr)))
  469.         FindHeader(text,"From:",recipStr, sizeof(recipStr));
  470.  
  471.     dlg = MyGetNewDialog(kRespDlg);
  472.     
  473.     DlgSetCString(dlg, 3, recipStr);
  474.     DlgSetCString(dlg, 4, subjectStr);
  475.  
  476.     SelIText(dlg,4,32000,32000);
  477.  
  478.     do {
  479.         DlgEnableItem(dlg, ok, *recipStr != 0 && *subjectStr != 0);
  480.         MyModalDialog(DialogFilter,&item,true,true);
  481.         DlgGetCString(dlg, 3, recipStr);
  482.         DlgGetCString(dlg, 4, subjectStr);
  483.     } while (item != ok && item != cancel);
  484.     
  485.     MyDisposDialog(dlg);
  486.  
  487.     if (item == cancel) return;
  488.  
  489.     strcpy(fromStr,gPrefs.address);
  490.     strcat(fromStr," (");
  491.     strcat(fromStr,gPrefs.fullName);
  492.     strcat(fromStr,")");
  493.         
  494.     c2pstr(subjectStr);
  495.     info = (TWindow**) GetWRefCon(newWind = 
  496.         MakeNewWindow(kMailMessage,firstOffset,(StringPtr)subjectStr));
  497.     p2cstr((StringPtr)subjectStr);
  498.         
  499.     (**info).changed = true;
  500.     IncludeQuote(wind,newWind,refStr);
  501.  
  502.     AddDateHeader(newWind);
  503.     AddHeader("From: ",fromStr,newWind);
  504.     AddHeader("To: ",recipStr,newWind);
  505.     if (gPrefs.replyCC) AddHeader("Cc: ",gPrefs.address,newWind);
  506.     AddHeader("Subject: ",subjectStr,newWind);
  507.     AddHeader("References: ",refStr,newWind);
  508.     AddHeader("Organization: ",gPrefs.organization,newWind);
  509.     AddEmptyLine(newWind);
  510.  
  511.     AddSignature(newWind);
  512.     InitHeaderDisplay(newWind);
  513.  
  514.     DoZoom(newWind,inZoomOut);
  515.     AdjustScrollBar(newWind);
  516.  
  517.     ShowWindow(newWind);
  518. }
  519.  
  520.  
  521. /*    MakePost creates a new article template for a new posting to a user-
  522.     specified newsgroup.
  523. */
  524.  
  525. void MakePost (WindowPtr wind)
  526. {
  527.     DialogPtr dlg;
  528.     short item;
  529.     TWindow **info;
  530.     WindowPtr newWind;
  531.     Point firstOffset;
  532.     CStr255 groupStr, distStr, subjectStr, followStr, messageID, path;
  533.     char fromStr[515];
  534.     ListHandle theList;
  535.     TGroup **groupArray;
  536.     short numSelected, cellData, cellDataLen;
  537.     Cell theCell;
  538.     Handle strings;
  539.     
  540.     if (!AreYouSure()) return;
  541.  
  542.     *groupStr = 0;
  543.     if (wind != nil) {
  544.         info = (TWindow**)GetWRefCon(wind);
  545.         switch ((**info).kind) {
  546.             case kFullGroup:
  547.             case kNewGroup:
  548.             case kUserGroup:
  549.                 theList = (**info).theList;
  550.                 groupArray = (**info).groupArray;
  551.                 strings = (**info).strings;
  552.                 SetPt(&theCell,0,0);
  553.                 numSelected = 0;
  554.                 while (LGetSelect(true,&theCell,theList)) {
  555.                     if (++numSelected > 1) break;
  556.                     cellDataLen = 2;
  557.                     LGetCell(&cellData, &cellDataLen, theCell, theList);
  558.                     strcpy(groupStr, *strings + (*groupArray)[cellData].nameOffset);
  559.                     theCell.v++;
  560.                 }
  561.                 if (numSelected != 1) *groupStr = 0;
  562.                 break;
  563.             case kSubject:
  564.                 GetWTitle(wind, (StringPtr)groupStr);
  565.                 p2cstr((StringPtr)groupStr);
  566.                 break;
  567.             case kArticle:
  568.                 if ((**info).parentWindow != nil) {
  569.                     GetWTitle((**info).parentWindow, (StringPtr)groupStr);
  570.                     p2cstr((StringPtr)groupStr);
  571.                 }
  572.                 break;
  573.         }
  574.     }
  575.     
  576.     dlg = MyGetNewDialog(kPostDlg);
  577.  
  578.     DlgSetCString(dlg, 3, groupStr);
  579.     DlgSetCString(dlg, 4, groupStr);
  580.     DlgSetCString(dlg, 5, "");
  581.  
  582.     if (*groupStr != 0) {
  583.         SelIText(dlg,6,32000,32000);
  584.     } else {
  585.         SelIText(dlg,3,0,0);
  586.     }
  587.  
  588.     do {
  589.         DlgEnableItem(dlg, ok, *groupStr != 0 && *subjectStr != 0);
  590.         MyModalDialog(DialogFilter,&item,true,true);
  591.         DlgGetCString(dlg, 3, groupStr);
  592.         DlgGetCString(dlg, 6, subjectStr);
  593.     } while (item != ok && item != cancel);
  594.     
  595.     if (item == ok) {
  596.         DlgGetCString(dlg, 4, followStr);
  597.         DlgGetCString(dlg, 5, distStr);
  598.     }
  599.  
  600.     MyDisposDialog(dlg);
  601.  
  602.     if (item == cancel) return;
  603.     
  604.     FixGroupList(groupStr);
  605.     FixGroupList(followStr);
  606.     
  607.     strcpy(fromStr,gPrefs.address);
  608.     strcat(fromStr," (");
  609.     strcat(fromStr,gPrefs.fullName);
  610.     strcat(fromStr,")");
  611.         
  612.     SetPt(&firstOffset,kOffLeft,kOffTop);
  613.     
  614.     c2pstr(subjectStr);
  615.     info = (TWindow**) GetWRefCon(newWind = 
  616.         MakeNewWindow(kPostMessage,firstOffset,(StringPtr)subjectStr));
  617.     p2cstr((StringPtr)subjectStr);
  618.         
  619.     (**info).changed = true;
  620.     
  621.     if(GetMyIPName(path) == noErr && strlen(path) <= 250) {
  622.         strcat(path,"!user");
  623.         AddHeader("Path: ",path,newWind);
  624.     } else {
  625.         AddHeader("Path: ","NewsWatcher!user",newWind);
  626.     }
  627.     AddDateHeader(newWind);
  628.     AddHeader("From: ",fromStr,newWind);
  629.     AddHeader("Newsgroups: ",groupStr,newWind);
  630.     AddHeader("Followup-To: ",followStr,newWind);
  631.     AddHeader("Distribution: ",distStr,newWind);
  632.     AddHeader("Subject: ",subjectStr,newWind);
  633.     
  634.     if(MakeMsgId(messageID) == noErr)
  635.         AddHeader("Message-ID: ", messageID, newWind);
  636.     AddHeader("Organization: ",gPrefs.organization,newWind);
  637.     AddEmptyLine(newWind);
  638.  
  639.     CheckNewsgroups(groupStr);
  640.     CheckSubject(subjectStr);
  641.     
  642.     AddSignature(newWind);
  643.     InitHeaderDisplay(newWind);
  644.  
  645.     DoZoom(newWind,inZoomOut);
  646.     AdjustScrollBar(newWind);
  647.  
  648.     ShowWindow(newWind);
  649. }
  650.